package com.duwei.util;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.util.ConverterUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.duwei.pojo.User;
import com.duwei.service.UserService;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Log4j2

public class UserExcelListener extends AnalysisEventListener<User> {

    private UserService userService;
    private ExcelWriter excelWriter;
    private WriteSheet writeSheet;
    public ResponseResult responseResult;

    public UserExcelListener(UserService userService){
        this.userService = userService;
    }
    public UserExcelListener(UserService userService, ExcelWriter excelWriter,WriteSheet writeSheet){
        this.userService = userService;
        this.excelWriter = excelWriter;
        this.writeSheet = writeSheet;
        responseResult = new ResponseResult();
    }

    public UserExcelListener(){

    }

    //固定每次收集100条，然后清理list，方便内存释放
    private static final int BATCH_COUNT = 5000;
    private static final int ERROR_COUNT = 5000;

    private List<User> errorList = new ArrayList<>(ERROR_COUNT);


    //缓存数据  类会扩容，所以可以直接设置大小
    private List<User> cacheList = new ArrayList<>(5001);








    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        if (exception instanceof ExcelDataConvertException) {
            log.error("======>>>解析异常：", exception);
            System.err.println("Data conversion error at row " + context.readRowHolder().getRowIndex());
            throw exception;
        }

    }

    /**
     * 当读取到一条数据时，就会调用这个方法，并将读取到的数据和上下文信息作为参数传入
     * 可以在这个方法里对数据进行处理
     * @param user
     * @param analysisContext
     */
    @SneakyThrows
    @Override
    public void invoke(User user, AnalysisContext analysisContext) {
        User count = userService.getOne(new QueryWrapper<User>().eq("count", user.getCount()));
        if(count != null){
            errorList.add(user);
            if(errorList.size() >= ERROR_COUNT){
                excelWriter.write(errorList,writeSheet);
                errorList.clear();
            }
            return;
        }

        cacheList.add(user);
        if(cacheList.size()>=BATCH_COUNT){
            //处理缓存数据，比如入库  mybatis-plus的saveBatch
            userService.saveBatch(cacheList);
            //为了防止插入数据重复，执行一条sql命令，删除重复数据，保留id值最小的数据行

            //清空缓存
            cacheList.clear();
        }

    }

    /**
     * 当每个sheet所有数据处理完毕以后，会调用，进行善后工作
     * @param analysisContext
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        userService.saveBatch(cacheList);
        cacheList.clear();
        excelWriter.write(errorList,writeSheet);
        errorList.clear();
        log.info("所有数据处理完毕");
    }

    /**
     * 解析表头数据
     * @param headMap
     * @param context
     */
    @Override
    public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
       log.info("表头数据:{}", ConverterUtils.convertToStringMap(headMap,context));
    }


}
